
#include <cstdio>
#include <string>



class FuncObjBase
{
public:
    virtual ~FuncObjBase()
    {
    }
    
    virtual void run()
    {
    }
};




template<typename _T, typename _FUNC, typename _ARG1, typename _ARG2>
class FuncObj2: public FuncObjBase
{
    _T *_obj;
    _FUNC _func;
    _ARG1 _arg1;
    _ARG2 _arg2;


public:
    FuncObj2(_FUNC func, _T *obj, _ARG1 arg1, _ARG2 arg2) 
        :_obj(obj),
        _func(func),
        _arg1(arg1),
        _arg2(arg2)
    {
    }

    void run() 
    {
        (_obj->*_func)(_arg1, _arg2);
    }
};

template<typename _FUNC, typename _ARG1>
class FuncObj3: public FuncObjBase
{
    _FUNC _func;
    _ARG1 _arg1;

public:
    FuncObj3(_FUNC func, _ARG1 arg1) 
        : _func(func),
        _arg1(arg1)
    {
    }

    void run() 
    {
        (_func)(_arg1);
    }
};



class Test
{
public:
    void print(int i, const std::string &s)
    {
        printf("%d %s\n", i, s.c_str());
    }
};


void T2(int x)
{
    printf("T2:%d\n", x);
}

template<typename _T, typename _FUNC, typename _ARG1, typename _ARG2>
FuncObjBase *bind(_FUNC func, _T *obj, _ARG1 arg1, _ARG2 arg2)
{
    return new FuncObj2<_T, _FUNC, _ARG1, _ARG2>(func, obj, arg1, arg2);
}

template<typename _FUNC, typename _ARG1>
FuncObjBase *bind(_FUNC func, _ARG1 arg1)
{
    return new FuncObj3<_FUNC, _ARG1>(func, arg1);
}


int main()
{
    Test test;
    FuncObjBase *func_obj = bind(&Test::print, &test, 12, "hello!Mew");
    func_obj->run();

    FuncObjBase *func_obj2 = bind(&T2,  12);
    func_obj2->run();
    return 0;
}


